#include "purg_sprng_interface.h"
#include <iostream>

namespace purg
{

  purgSprng::purgSprng ()
  {
    _purg = 0;
  }

  purgSprng::~purgSprng ()
  {
    if ( _purg )
      delete _purg;
  }

  int purgSprng::init_rng ( int id , int , int seed , int )
  {
    if ( _purg )
      delete _purg;
    _id = id;
    _seed = seed;
    _purg = new parallel_gen ( seed , 0 , id );
    return 1;
  }

  int purgSprng::get_rn_int ()
  {
    unsigned int retVal;
    _purg->get ( retVal , 0 , (1<<31) );
    return static_cast<int> ( retVal );
  }

  float purgSprng::get_rn_flt ()
  {
    float retVal;
    _purg->get ( retVal , 0. , 1. );
    return retVal;
  }

  float purgSprng::get_rn_dbl ()
  {
    double retVal;
    _purg->get ( retVal , 0. , 1. );
    return retVal;
  }

  int purgSprng::spawn_rng ( int nspawned , Sprng ***newgens )
  {
    *newgens = new purgSprng [ nspawned ];
    for ( int i = 0 ; i != nspawned ; i++ )
    {
      (*newgens)[i] = new purgSprng;
      (*newgens)[i]->init_rng ( _id , 0 , _seed , 0 );
    }
    return 1;
  }

  int purgSprng::get_seed_rng ()
  {
    return 0;
  }

  int purgSprng::free_rng ()
  {
    if ( _purg )
      delete _purg;
    _purg = 0;
    return 1;
  }

  int purgSprng::pack_rng ( char **buffer )
  {
    buffer  &state_buf = _purg->get_gen1_state().buffer;
    *buf = new char [ 2*sizeof(int) + 2*sizeof(size_t) + state_buf.size() ];
    int *len = static_cast<int *> ( *buf );
    int *seed_ptr = static_cast<int *> ( (*buf) + sizeof(int) );
    size_t *id = static_cast<size_t *> ( (*buf) + 2*sizeof(int) );
    size_t *iteration = static_cast<size_t *> ( (*buf) + 2*sizeof(int) + sizeof ( size_t ));
    unsigned char tbuf = static_cast<unsigned int *> ( (*buf) + 2*sizeof(int) + 2*sizeof ( size_t ));
    state_buf.copyTo ( static_cast<void *> ( tbuf ) , 0 , 0 , state_buf.size() );
    *len = *(_purg->get_gen1_state()._length);
    *seed_ptr = *(_purg->get_gen1_state()._seed_ptr);
    *id = *(_purg->get_gen1_state()._id);
    *iteration = *(_purg->get_gen1_state()._iteration);
    return 1;
  }

  int purgSprng::unpack_rng ( char **buffer )
  {
    buffer  &state_buf = _purg->get_gen1_state().buffer;
    *buf = new char [ 2*sizeof(int) + 2*sizeof(size_t) + state_buf.size() ];
    int *len = static_cast<int *> ( *buf );
    int *seed_ptr = static_cast<int *> ( (*buf) + sizeof(int) );
    size_t *id = static_cast<size_t *> ( (*buf) + 2*sizeof(int) );
    size_t *iteration = static_cast<size_t *> ( (*buf) + 2*sizeof(int) + sizeof ( size_t ));
    unsigned char tbuf = static_cast<unsigned int *> ( (*buf) + 2*sizeof(int) + 2*sizeof ( size_t ));
    memcpy ( &(state_buf[0]) , tbuf , state_buf.size() );
    *(_purg->get_gen1_state()._length) = *len;
    *(_purg->get_gen1_state()._seed_ptr) = *seed_ptr;
    *(_purg->get_gen1_state()._id) = *id;
    *(_purg->get_gen1_state()._iteration) = *iteration;
    return 1;
  }

  int purgSprng::print_rng ()
  {
    std::cout << "Purg ID: " << _id << " Seed: " << _seed << " Iteration: " << *(_purg->get_gen1_state().iteration) << std::endl;
  }

}
